home *** CD-ROM | disk | FTP | other *** search
- /* protz.c Version 1.5, 92Apr24 */
- /* Modified by Ian Lance Taylor for Taylor UUCP 1.04 92Aug4. */
-
- /*
- * Doug Evans, dje@sspiff.UUCP or dje@ersys.edmonton.ab.ca
- *
- * This file provides the Zmodem protocol (by Chuck Forsberg) for
- * Ian Taylor's UUCP package.
- *
- * It was originally developed to establish a uucp link between myself and my
- * employer: Ivation Datasystems, Inc. of Ottawa.
- *
- * My thanks to Ivation for letting me release this to the public. Given that
- * Zmodem is in the public domain, no additional copyrights have been added.
- *
- *****************************************************************************
- *
- * It's been difficult fitting Zmodem into the UUCP world. I have been guided
- * mostly by trying to plug it into Taylor UUCP. Where "the Zmodem way of doing
- * things" conflicted with "the UUCP way of doing things", I have err'd on the
- * side of UUCP. At the end of it all, I have achieved something that will plug
- * into Taylor UUCP very easily, but some might argue that I have corrupted Z
- * too much. At any rate, compatibility with sz/rz was sacrificed to achieve a
- * clean UUCP protocol. Given that, I took the opportunity to start from
- * scratch when defining protocol constants (EG: ZBIN).
- *
- * 1) I wasn't quite sure how to enhance Zmodem to handle send+receive in one
- * session, so I added a 'g' protocol like initialization sequence. This
- * also gets this stuff out of the way, in case we ever try to support
- * full-duplex.
- *
- * Caller Callee
- * ------ ------
- * ZINIT --> <-- ZINIT
- * ZDATA (ZCRCF) --> <-- ZDATA (ZCRCF)
- * ZACK --> <-- ZACK
- * ZINITEND --> <-- ZINITEND
- *
- * ZINIT is a combination of ZRINIT and ZSINIT and is intended to exchange
- * simple protocol information (flags) and the protocol version number.
- * ZDATA is intended to include window size information as well as the
- * "Myattn" string (although at the moment it doesn't contain anything).
- * ZDATA may contain at most 1k bytes of data and is sent out as one ZCRCF
- * packet. Two ack's (ZACK + ZINITEND) are needed to ensure both sides have
- * received ZDATA.
- *
- * 2) I've hardcoded several protocol parameters, like 32 bit CRC's for data.
- * Others are not supported (we don't need them).
- *
- * 3) ZHEX headers use 32 bit CRC's.
- *
- * 4) Zmodem sends the ZFILE message "in one chunk". If there are errors, the
- * entire string is resent. I have continued this practice. All UUCP
- * commands are sent "in one chunk". This can be changed down the road if
- * necessary.
- *
- * 5) The ZEOF message has been replaced with a new ZCRCx value: ZCRCF. ZCRCF
- * is identical to ZCRCW except that it indicates the end of the message.
- * The protocol here is *not* a file transfer protocol. It is an end to end
- * transport protocol (that preserves message boundaries).
- *
- * 6) Zmodem handles restarting a file transfer, but as best as I can tell UUCP
- * does not. At least Taylor UUCP doesn't. And if UUCP does start handling
- * file restart, can it be plugged into the existing Zmodem way with zero
- * changes? Beats me. Therefore I have removed this part of the code. One
- * can always put it back in if and when UUCP handles it. Ditto for other
- * pieces of removed code: there's no point in overly complicating this code
- * when supporting all the bells and whistles requires enhancements to UUCP
- * itself.
- *
- * *** It is easier to put code back in in an upward compatible manner ***
- * *** than it is to correct for misunderstood code or poorly merged ***
- * *** (Zmodem vs UUCP) code. ***
- *
- * 7) For the character in the initial "protocol selection" sequence, I have
- * chosen 'a'. I'm told 'z' is already in use for something that isn't
- * Zmodem. It's entirely reasonable to believe that if Zmodem ever becomes a
- * standard UUCP protocol, this won't be it (so I'll leave z/Z for them).
- * Publicly, this is the 'a' protocol. Internally, it is refered to as 'z'.
- * A little confusing, I know. Maybe in time I'll refer to it internally as
- * 'a', or maybe in time this will be *the* 'z' protocol.
- *
- * 8) Since we are writing a transport protocol, which isn't supposed to know
- * anything about what is being transfered or where it is coming from, the
- * header data value has changed meaning. It no longer means "file position"
- * but instead means "window position". It is a running counter of the bytes
- * transfered. Each "message" begins on a 1k boundary so the count isn't a
- * precise byte count. The counter wraps every 4 gigabytes, although this
- * wrapping isn't supported yet.
- *
- * FIXME: At present the max data transfered per session is 4 gigabytes.
- *
- ****************************************************************************
- *
- * A typical message sequence is (master sending file to slave):
- *
- * Master Slave
- * ------ -----
- * ZDATA (S, ZCRCF) -->
- * <-- ZACK
- * <-- ZDATA (SY, ZCRCF)
- * ZACK -->
- * ZDATA -->
- * ... <-- ZACK/ZRPOS
- * ZDATA (ZCRCF) -->
- * <-- ZACK
- * <-- ZDATA (CY, ZCRCF)
- * ZACK -->
- *
- * A typical message sequence is (master receiving file from slave):
- *
- * Master Slave
- * ------ -----
- * ZDATA (R, ZCRCF) -->
- * <-- ZACK
- * <-- ZDATA (RY, ZCRCF)
- * ZACK -->
- * <-- ZDATA
- * ZACK/ZRPOS ... -->
- * <-- ZDATA (ZCRCF)
- * ZACK -->
- * ZDATA (CY, ZCRCF) -->
- * <-- ZACK
- *
- *****************************************************************************
- *
- * Notes:
- * 1) For future bidirectional concerns, keep packet types "unidirectional".
- * Sender always uses: ZDATA, ZNAK
- * Receiver always uses: ZRPOS, ZACK
- * There is no intersection.
- *
- * I'm not sure if this is necessary or even useful, but it seems to be.
- *
- * 2) I use to store the byte count / 32 in the data header. This left 5 bits
- * unused for future concerns. I removed this because of the following
- * situation when sending a file:
- *
- * ZDATA (ZCRCG, xx bytes) - received ok
- * ZDATA (ZCRCF, 0 bytes) - corrupted
- *
- * At this point the receiver would like to send back a ZRPOS with a value
- * of the size of the file. However, it can't because the value is divided
- * by 32, and it would have to round up to the next multiple of 32. This
- * seemed a little ugly, so I went with using the entire header to store
- * the byte count.
- *
- *****************************************************************************
- *
- * Source version:
- *
- * 1.1,2,3
- * Protocol version 0
- * Early attempts, completely rewritten later.
- *
- * 1.4 Protocol version 1
- * Beta test sent to Ian for analysis 92Apr18.
- *
- * 1.5 Protocol version 1
- * Released 92Apr24.
- *
- *****************************************************************************
- *
- * Protocol version:
- *
- * A version number is exchanged in the ZINIT message, so it is possible to
- * correct or enhance the protocol, without breaking existing versions.
- * The purpose of this section is to document these versions as they come out.
- * Remember, this is the protocol version, not the source version.
- *
- * 0 Initial version.
- * Zmodem controlled file transfer. This was more of a "plug Z
- * into UUCP as is" port.
- *
- * 1 Complete rewrite.
- * Made Z more of a transport protocol. UUCP now controls transfer and Z
- * is on the same footing as the other UUCP protocols.
- * Theoretically, there will be little pain when UUCP goes bidirectional.
- */
-
- #include "uucp.h"
-
- #if USE_RCS_ID
- const char protz_rcsid[] = "$Id: protz.c,v 1.8 1993/12/20 00:44:49 ian Rel $";
- #endif
-
- #include <errno.h>
-
- #include "uudefs.h"
- #include "uuconf.h"
- #include "conn.h"
- #include "trans.h"
- #include "system.h"
- #include "prot.h"
-
- #define ZPROTOCOL_VERSION 1
-
- /*
- * Control message characters ...
- */
-
- #define ZPAD '*' /* Padding character begins frames */
- #define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */
- #define ZBIN 'A' /* Binary frame indicator */
- #define ZHEX 'B' /* HEX frame indicator */
-
- /*
- * Frame types (see array "frametypes" in zm.c) ...
- *
- * Note that the numbers here have been reorganized, as we don't support
- * all of them (nor do we need to).
- *
- * WARNING: The init sequence assumes ZINIT < ZDATA < ZACK < ZINITEND.
- */
-
- #define ZINIT 0 /* Init (contains protocol version, flags) */
- #define ZDATA 1 /* Data packet(s) follow */
- #define ZRPOS 2 /* Resume data trans at this position */
- #define ZACK 3 /* ACK to above */
- #define ZNAK 4 /* Last packet was garbled */
- #define Zreserved 5 /* reserved (for future concerns) */
- #define ZINITEND 6 /* end of init sequence */
- #define ZFIN 7 /* Finish session */
-
- /*
- * ZDLE sequences ...
- *
- * Note addition of ZCRCF: "end of message".
- */
-
- #define ZCRCE 'h' /* CRC next, frame ends, header packet follows */
- #define ZCRCG 'i' /* CRC next, frame continues nonstop */
- #define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */
- #define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */
- #define ZCRCF 'l' /* CRC next, ZACK expected, end of message */
-
- #define ZRUB0 'm' /* Translate to rubout 0177 */
- #define ZRUB1 'n' /* Translate to rubout 0377 */
-
-
- /*
- * zdlread return values (internal) ...
- * Other values are ZM_ERROR, ZM_TIMEOUT, ZM_RCDO.
- */
-
- #define GOTOR 0400
- #define GOTCRCE (ZCRCE | GOTOR) /* ZDLE-ZCRCE received */
- #define GOTCRCG (ZCRCG | GOTOR) /* ZDLE-ZCRCG received */
- #define GOTCRCQ (ZCRCQ | GOTOR) /* ZDLE-ZCRCQ received */
- #define GOTCRCW (ZCRCW | GOTOR) /* ZDLE-ZCRCW received */
- #define GOTCRCF (ZCRCF | GOTOR) /* ZDLE-ZCRCF received */
-
- /*
- * Byte positions within header array ...
- */
-
- #define ZF0 3 /* First flags byte */
- #define ZF1 2
- #define ZF2 1
- #define ZF3 0
-
- #define ZP0 0 /* Low order 8 bits of position */
- #define ZP1 1
- #define ZP2 2
- #define ZP3 3 /* High order 8 bits of position */
-
- /*
- * Bit Masks for ZRQINIT flags byte ZF0 ...
- */
-
- #define TX_ESCCTL 1 /* Tx will escape control chars */
-
- /*
- * Possible errors when running ZMODEM ...
- */
-
- #define ZM_ERROR (-1) /* crc error, etc. */
- #define ZM_TIMEOUT (-2)
- #define ZM_RCDO (-3) /* Carrier Lost */
-
- /*
- * ASCII characters ...
- */
-
- #define LF 012
- #define CR 015
- #define XON 021
- #define XOFF 023
-
- #define XON_WAIT 10 /* seconds */
-
- /*
- * Packet sizes ...
- *
- * FIXME: CPACKETSIZE is hardcoded in a lot of places.
- * It's not clear to me whether changing it's value would be a
- * "good thing" or not. But of course that doesn't excuse the hardcoding.
- */
-
- #define CPACKETSIZE 1024 /* max packet size (data only) */
- #define CFRAMELEN 12 /* header size */
- #define CSUFFIXLEN 10 /* suffix at end of data packets */
- #define CEXCHANGE_INIT_RETRIES 4
-
- /* The header CRC value. */
-
- #if ANSI_C
- #define IHDRCRC 0xDEBB20E3UL
- #else
- #define IHDRCRC ((unsigned long) 0xDEBB20E3L)
- #endif
-
- /* packet buffer size */
- #define CPACKBUFSIZE (CFRAMELEN + 2 * CPACKETSIZE + CSUFFIXLEN + 42 /*slop*/)
-
- /*
- * Data types ...
- */
-
- typedef unsigned char achdrval_t[4];
- typedef unsigned long hdrval_t;
- typedef unsigned long winpos_t;
-
- /*
- * Configurable parms ...
- *
- * FIXME: <cZrx_buf_len> isn't used yet. It may not be needed.
- */
-
- #define CTIMEOUT 10
- #define CRETRIES 10
- #define CSTARTUP_RETRIES 4
- #define CGARBAGE 2400
- #define CSEND_WINDOW 16384
- #define FESCAPE_CONTROL FALSE
-
- static int cZtimeout = CTIMEOUT; /* (seconds) */
- static int cZretries = CRETRIES;
- static int cZstartup_retries = CSTARTUP_RETRIES;
- static int cZmax_garbage = CGARBAGE; /* max garbage before header */
- static int cZtx_window = CSEND_WINDOW; /* our transmission window */
- static int cZrx_buf_len = 0; /* our reception buffer size */
- static boolean fZesc_ctl = FESCAPE_CONTROL; /* escape control chars */
-
- struct uuconf_cmdtab asZproto_params[] =
- {
- {"timeout", UUCONF_CMDTABTYPE_INT, (pointer) & cZtimeout, NULL},
- {"retries", UUCONF_CMDTABTYPE_INT, (pointer) & cZretries, NULL},
- {"startup-retries", UUCONF_CMDTABTYPE_INT,
- (pointer) & cZstartup_retries, NULL},
- {"garbage", UUCONF_CMDTABTYPE_INT, (pointer) & cZmax_garbage, NULL},
- {"send-window", UUCONF_CMDTABTYPE_INT, (pointer) & cZtx_window, NULL},
- {"escape-control", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) & fZesc_ctl,
- NULL},
- {NULL, 0, NULL, NULL}
- };
-
- /*
- * Variables for statistic gathering ...
- *
- * We use <wpZtxpos, wpZrxbytes> to record the number of "packets"
- * sent/received. Packets is in double quotes because some of them aren't full.
- */
-
- static unsigned long cZheaders_sent;
- static unsigned long cZheaders_received;
- static unsigned long cZbytes_resent;
- static unsigned long cZtimeouts;
- static unsigned long cZerrors;
-
- /*
- * Data buffers ...
- */
-
- static char *zZtx_buf; /* transmit buffer */
-
- static char *zZtx_packet_buf; /* raw outgoing packet data */
- static char *zZrx_packet_buf; /* raw incoming packet data */
-
- /*
- * Transmitter state variables ...
- */
-
- static unsigned cZblklen; /* data length in sent/received packets */
- static unsigned cZtxwspac; /* spacing between ZCRCQ requests */
- /*static unsigned cZblklen_override;*//* override value for <cZblklen> */
- static unsigned cZtxwcnt; /* counter used to space ack requests */
- static unsigned cZrxwcnt; /* counter used to watch receiver's buf size */
- static winpos_t wpZtxstart; /* <wpZtxpos> when message started */
- static winpos_t wpZtxpos; /* transmitter position */
- static winpos_t wpZlastsync; /* last offset to which we got a ZRPOS */
- static winpos_t wpZlrxpos; /* receiver's last reported offset */
- static winpos_t wpZrxpos; /* receiver file position */
-
- static int iZlast_tx_data_packet; /* type of last ZDATA packet (ZCRCx) */
- static int iZjunk_count; /* amount of garbage characters received */
- static int iZtleft; /* for dynamic packet resizing */
-
- static int iZbeenhereb4; /* times we've been ZRPOS'd to same place */
-
- /*
- * Receiver state variables ...
- */
-
- static winpos_t wpZrxbytes; /* receiver byte count */
- static int iZlast_rx_data_packet; /* last successfully received ZCRCx packet */
-
- /*
- * Misc. globals ...
- */
-
- static char xon = XON;
-
- #ifdef DJE_TESTING
- int uucptest = -1;
- int uucptest2;
- int uucptestseed;
- #endif
-
- /*
- * Kludge!!!
- * See fzfinish_tx(). Basically the next two globals are used to record the
- * fact that we got a ZDATA, but aren't quite ready to process it.
- */
-
- static int iZpkt_rcvd_kludge; /* -1 if not valid */
- static hdrval_t hvZpkt_hdrval_kludge;
-
- /*
- * Packet types ...
- */
-
- static const char *azZframe_types[] = {
- "Carrier Lost", /* -3 */
- "Timeout", /* -2 */
- "Error", /* -1 */
- #define FTOFFSET 3
- "ZINIT",
- "ZDATA",
- "ZRPOS",
- "ZACK",
- "ZNAK",
- "Zreserved",
- "ZINITEND",
- "ZFIN",
- "UNKNOWN!!!"
- };
- #define FTNUMBER (sizeof(azZframe_types) / sizeof(char *))
-
- #ifndef min
- #define min(a, b) ((a) < (b) ? (a) : (b))
- #endif
- #define ZZHEADER_NAME(itype) \
- azZframe_types[min((itype) + FTOFFSET, FTNUMBER - 1)]
-
- /*
- * Local functions ...
- */
-
- static boolean fzsend_data P((struct sdaemon *qdaemon, char *zdata,
- size_t cdata, boolean fendofmessage));
- static boolean fzprocess P((struct sdaemon *qdaemon));
- static boolean fzstart_proto P((struct sdaemon *qdaemon));
- static int izexchange_init P((struct sdaemon *qdaemon, int send_type,
- achdrval_t send_val, achdrval_t recv_val));
- static boolean fzshutdown_proto P((struct sdaemon *qdaemon));
- static boolean fzstart_tx P((void));
- static boolean fzfinish_tx P((struct sdaemon *qdaemon, long *plredo));
- static boolean fzstart_rx P((void));
- static boolean fzfinish_rx P((struct sdaemon *qdaemon));
- static boolean fzsend_hdr P((struct sdaemon *qdaemon, int ipkttype,
- int ihdrtype, hdrval_t hdrval,
- boolean fcheckreceive));
- static boolean fzsend_data_packet P((struct sdaemon *qdaemon, char *zdata,
- size_t cdata, int frameend,
- boolean fcheckreceive));
- static int czbuild_header P((char *zresult, int ipkttype, int ihdrtype,
- hdrval_t hdrval));
- static int czbuild_data_packet P((char *zresult, const char *zdata,
- size_t cdata, int frameend));
- /*
- * The rest of the functions do not follow Ian's naming style. I have left
- * the names the same as the original zm source. Over time, they may change.
- */
- static int izrecv_hdr P((struct sdaemon *qdaemon, achdrval_t hdr));
- static int zrbhdr32 P((struct sdaemon *qdaemon, achdrval_t hdr));
- static int zrhhdr P((struct sdaemon *qdaemon, achdrval_t hdr));
- static int zrdat32 P((struct sdaemon *qdaemon, char *buf, int length,
- int *iprxcount));
- static int getinsync P((struct sdaemon *qdaemon, boolean flag));
- static char *zputhex P((char *p, int ch));
- static char *zputchar P((char *p, int ch));
- static int zgethex P((struct sdaemon *qdaemon));
- static int zdlread P((struct sdaemon *qdaemon));
- static int noxrd7 P((struct sdaemon *qdaemon));
- static int realreadchar P((struct sdaemon *qdaemon, int timeout));
- static boolean fzreceive_ready P((void));
- static void stohdr P((hdrval_t pos, achdrval_t hdr));
- static hdrval_t rclhdr P((achdrval_t hdr));
- static hdrval_t hvzencode_data_hdr P((winpos_t cbytes));
- static void zdecode_data_hdr P((hdrval_t hdrval, winpos_t *pcbytes));
- static winpos_t lzupdate_rxpos P((achdrval_t rx_hdr, winpos_t rxpos,
- winpos_t lrxpos, winpos_t txpos));
-
- /*
- * This macro replaces readchar() because it achieves a noticable speed up. The
- * readchar() function has been renamed realreadchar(). Thanks to Ian for
- * running this stuff through a profiler to find this out. Ian suggests further
- * speed ups may be obtained by doing a similar thing in zrdat32().
- */
-
- /* Assign the next character to b. */
- #define READCHAR(qdaemon, b, i) \
- (iPrecstart != iPrecend \
- ? ((b) = BUCHAR (abPrecbuf[iPrecstart]), \
- iPrecstart = (iPrecstart + 1) % CRECBUFLEN) \
- : ((b) = realreadchar ((qdaemon), (i))))
-
- /************************************************************************/
-
-
- /*
- * Start the protocol ...
- */
-
- boolean
- fzstart(qdaemon, pzlog)
- struct sdaemon *qdaemon;
- char **pzlog;
- {
- *pzlog = zbufalc (sizeof "protocol 'a' starting: , , , , , " + 100);
- sprintf (*pzlog, "protocol 'a' starting: %d, %d, %d, %d, %d, %d",
- cZtimeout, cZretries, cZstartup_retries,
- cZmax_garbage, cZtx_window, fZesc_ctl);
-
- if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE,
- STRIPSETTING_EIGHTBITS, XONXOFF_OFF))
- return FALSE;
-
- /*
- * For now, we place tight restrictions on the size of the transmit
- * window. This might be relaxed in the future. If it is relaxed,
- * some of these tests will stay, some will go. That is why it is
- * coded like it is.
- */
-
- if (cZtx_window % 1024 != 0 ||
- cZtx_window < 4096 || cZtx_window > 65536 ||
- 65536 % cZtx_window != 0
- ) {
- ulog (LOG_ERROR,
- "fzstart: cZtx_window not one of 4096, 8192, 16384, 32768, 65536");
- return FALSE;
- }
-
- zZtx_buf = (char *) xmalloc (CPACKETSIZE);
- zZtx_packet_buf = (char *) xmalloc (CPACKBUFSIZE);
- zZrx_packet_buf = (char *) xmalloc (CPACKBUFSIZE);
-
- iZlast_tx_data_packet = -1;
- iZlast_rx_data_packet = -1;
-
- wpZtxpos = wpZlrxpos = wpZrxpos = wpZrxbytes = 0;
- cZtxwspac = cZtx_window / 4;
-
- cZheaders_sent = cZheaders_received = cZbytes_resent = 0;
- cZtimeouts = cZerrors = 0;
-
- iZpkt_rcvd_kludge = -1;
-
- #if 0
- /*
- * We ensure <cZtx_window> is at least 4k, so the following is
- * unnecessary. It can be put back in later if needed.
- */
- if (cZblklen_override > cZtxwspac
- || (!cZblklen_override && cZtxwspac < 1024))
- cZblklen_override = cZtxwspac;
- #endif
-
- #ifdef DJE_TESTING
- {
- extern int uucptest,uucptest2,uucptestseed;
- FILE *f;
-
- if (uucptest == -1) {
- f = fopen ("/usr/local/src/bin/uucp/uucptest", "r");
- if (f != NULL) {
- fscanf (f, "%d %d %d",
- &uucptestseed, &uucptest, &uucptest2);
- fclose (f);
- }
- srand (uucptestseed);
- }
- }
- #endif
-
- /*
- * Fire up the protocol (exchange init messages) ...
- */
-
- if (!fzstart_proto (qdaemon))
- return FALSE;
-
- return TRUE;
- }
-
- /*
- * Stop the protocol ...
- */
-
- boolean
- fzshutdown(qdaemon)
- struct sdaemon *qdaemon;
- {
- (void) fzshutdown_proto (qdaemon);
-
- xfree ((pointer) zZtx_buf);
- xfree ((pointer) zZtx_packet_buf);
- xfree ((pointer) zZrx_packet_buf);
- zZtx_buf = NULL;
- zZtx_packet_buf = NULL;
- zZrx_packet_buf = NULL;
-
- /*
- * Print some informative statistics ...
- *
- * I use the word "messages" here instead of "headers" because the
- * latter is jargonese.
- */
-
- ulog (LOG_NORMAL,
- "Protocol 'a' messages: sent %lu, received %lu",
- cZheaders_sent, cZheaders_received);
- ulog (LOG_NORMAL,
- "Protocol 'a' packets: sent %lu, received %lu",
- wpZtxpos / 1024, wpZrxbytes / 1024);
- if (cZbytes_resent != 0 || cZtimeouts != 0 || cZerrors != 0)
- ulog (LOG_NORMAL,
- "Protocol 'a' errors: bytes resent %lu, timeouts %lu, errors %lu",
- cZbytes_resent, cZtimeouts, cZerrors);
-
- /*
- * Reset all the parameters to their default values, so that the
- * protocol parameters used for this connection do not affect the
- * next one.
- */
-
- cZtimeout = CTIMEOUT;
- cZretries = CRETRIES;
- cZstartup_retries = CSTARTUP_RETRIES;
- cZmax_garbage = CGARBAGE;
- cZtx_window = CSEND_WINDOW;
- fZesc_ctl = FESCAPE_CONTROL;
-
- cZheaders_sent = cZheaders_received = cZbytes_resent = 0;
- cZtimeouts = cZerrors = 0;
-
- return TRUE;
- }
-
- /*
- * Send a command string ...
- * We send everything up to and including the null byte.
- *
- * We assume the command will fit in the outgoing data buffer.
- * FIXME: A valid assumption?
- */
-
- /*ARGSUSED*/
- boolean
- fzsendcmd(qdaemon, z, ilocal, iremote)
- struct sdaemon *qdaemon;
- const char *z;
- int ilocal;
- int iremote;
- {
- size_t n,clen;
- long lredo;
- char *zbuf;
-
- clen = strlen (z) + 1;
-
- DEBUG_MESSAGE1 (DEBUG_PROTO, "fzsendcmd: sending command %s", z);
-
- if (!fzstart_tx ()) /* must be called before zzgetspace() */
- return FALSE;
-
- if ((zbuf = zzgetspace (qdaemon, &n)) == NULL)
- return FALSE;
-
- #if DEBUG > 0
- if (clen > n)
- ulog (LOG_FATAL, "fzsendcmd: clen > n");
- #endif
-
- strcpy (zbuf, z);
-
- /*
- * Send it out ...
- */
-
- do {
- if (!fzsend_data (qdaemon, zbuf, clen, TRUE))
- return FALSE;
- if (!fzfinish_tx (qdaemon, &lredo))
- return FALSE;
- } while (lredo >= 0);
-
- return fzprocess (qdaemon);
- }
-
- /*
- * Allocate a packet to send out ...
- *
- * Note that 'z' has dynamic packet resizing and that <cZblklen> will range
- * from 32 to 1024, in multiples of 2.
- */
-
- /*ARGSUSED*/
- char *
- zzgetspace(qdaemon, pclen)
- struct sdaemon *qdaemon;
- size_t *pclen;
- {
- *pclen = cZblklen;
- return zZtx_buf;
- }
-
- /*
- * Send a block of data ...
- *
- * If (cdata == 0) then the end of the file has been reached.
- */
-
- /*ARGSUSED*/
- boolean
- fzsenddata(qdaemon, zdata, cdata, ilocal, iremote, ipos)
- struct sdaemon *qdaemon;
- char *zdata;
- size_t cdata;
- int ilocal;
- int iremote;
- long ipos;
- {
- DEBUG_MESSAGE1 (DEBUG_PROTO, "fzsenddata: %d bytes", cdata);
-
- if (! fzsend_data (qdaemon, zdata, cdata, cdata == 0))
- return FALSE;
- return fzprocess (qdaemon);
- }
-
- /*
- * Send a block of data (command or file) ...
- */
-
- /* This should buffer the data internally. Until it does, it needs to
- be able to reset the file position when it is called. This is
- really ugly. */
- extern struct stransfer *qTsend;
-
- static boolean
- fzsend_data(qdaemon, zdata, cdata, fendofmessage)
- struct sdaemon *qdaemon;
- char *zdata;
- size_t cdata;
- boolean fendofmessage;
- {
- size_t n;
-
- if (iZlast_tx_data_packet == -1 || iZlast_tx_data_packet == ZCRCW) {
- cZtxwcnt = cZrxwcnt = 0;
- iZjunk_count = 0;
- if (!fzsend_hdr (qdaemon, ZBIN, ZDATA,
- hvzencode_data_hdr (wpZtxpos), TRUE))
- return FALSE;
- }
-
- n = cdata;
-
- if (fendofmessage)
- iZlast_tx_data_packet = ZCRCF;
- else if (iZjunk_count > 3)
- iZlast_tx_data_packet = ZCRCW;
- else if (wpZtxpos == wpZlastsync)
- iZlast_tx_data_packet = ZCRCW;
- else if (cZrx_buf_len && (cZrxwcnt += n) >= cZrx_buf_len)
- iZlast_tx_data_packet = ZCRCW;
- else if ((cZtxwcnt += n) >= cZtxwspac) {
- iZlast_tx_data_packet = ZCRCQ;
- cZtxwcnt = 0;
- } else
- iZlast_tx_data_packet = ZCRCG;
-
- if (++iZtleft > 3) {
- iZtleft = 0;
- if (cZblklen < 1024)
- cZblklen *= 2;
- #if 0 /* <cZblklen_override> is currently unnecessary */
- if (cZblklen_override && cZblklen > cZblklen_override)
- cZblklen = cZblklen_override;
- #endif
- if (cZblklen > 1024)
- cZblklen = 1024;
- if (cZrx_buf_len && cZblklen > cZrx_buf_len)
- cZblklen = cZrx_buf_len;
- }
-
- #if DEBUG > 1
- if (FDEBUGGING(DEBUG_PROTO)) {
- const char *type;
-
- switch (iZlast_tx_data_packet) {
- case ZCRCW: type = "ZCRCW"; break;
- case ZCRCG: type = "ZCRCG"; break;
- case ZCRCQ: type = "ZCRCQ"; break;
- case ZCRCE: type = "ZCRCE"; break;
- case ZCRCF: type = "ZCRCF"; break;
- default : type = "UNKNOWN!!!"; break;
- }
- DEBUG_MESSAGE3 (DEBUG_PROTO,
- "fzsend_data: %s, pos 0x%lx, %d bytes",
- type, wpZtxpos, n);
- }
- #endif
-
- if (!fzsend_data_packet (qdaemon, zdata, n, iZlast_tx_data_packet,
- TRUE))
- return FALSE;
-
- wpZtxpos += n;
-
- if (iZlast_tx_data_packet == ZCRCW) {
- /*
- * FIXME: Ideally this would be done in fzprocess. However, it
- * is only called if there is data pending which there
- * may not be yet. I could have patched fploop() a bit but
- * for now, I've done it like this.
- */
- switch (getinsync (qdaemon, FALSE)) {
- case ZACK:
- break;
- case ZRPOS:
- if (qTsend == NULL
- || ! ffileisopen (qTsend->e)) {
- ulog (LOG_ERROR, "Can't reset non-file");
- return FALSE;
- }
- iZlast_tx_data_packet = -1; /* trigger ZDATA */
- DEBUG_MESSAGE1 (DEBUG_PROTO,
- "fzsend_data: Seeking to %ld",
- (long) (wpZrxpos - wpZtxstart));
- if (!ffileseek (qTsend->e, wpZrxpos - wpZtxstart)) {
- ulog (LOG_ERROR, "seek: %s", strerror (errno));
- return FALSE;
- }
- break;
- default:
- return FALSE;
- }
- return TRUE;
- }
-
- /*
- * If we've reached the maximum transmit window size, let the
- * receiver catch up ...
- *
- * I use (cZtx_window - 2048) to play it safe.
- */
-
- while (wpZtxpos - wpZlrxpos >= cZtx_window - 2048) {
- if (iZlast_tx_data_packet != ZCRCQ) {
- if (!fzsend_data_packet (qdaemon, zdata, (size_t) 0,
- iZlast_tx_data_packet = ZCRCQ,
- TRUE))
- return FALSE;
- }
- /*
- * FIXME: I'd rather not call ffileseek() in this file. When we
- * start buffering the outgoing data, the following
- * ffileseek() will disappear.
- */
- switch (getinsync (qdaemon, TRUE)) {
- case ZACK:
- break;
- case ZRPOS:
- if (qTsend == NULL
- || ! ffileisopen (qTsend->e)) {
- ulog (LOG_ERROR, "Can't reset non-file");
- return FALSE;
- }
- iZlast_tx_data_packet = -1; /* trigger ZDATA */
- DEBUG_MESSAGE1 (DEBUG_PROTO,
- "fzsend_data: Seeking to %ld",
- (long) (wpZrxpos - wpZtxstart));
- if (!ffileseek (qTsend->e, wpZrxpos - wpZtxstart)) {
- ulog (LOG_ERROR, "seek: %s", strerror (errno));
- return FALSE;
- }
- break;
- default:
- return FALSE;
- }
- }
-
- return TRUE;
- }
-
- /*
- * Process existing data ...
- */
-
- static boolean
- fzprocess(qdaemon)
- struct sdaemon *qdaemon;
- {
- int c,ch;
-
- while (fzreceive_ready ()) {
- READCHAR (qdaemon, ch, 1);
- switch (ch) {
- case ZPAD:
- /* see if we're detecting ZRPOS packets quickly */
- DEBUG_MESSAGE0 (DEBUG_PROTO,
- "fzprocess: possible ZRPOS packet");
- /* We just ate the ZPAD char that getinsync
- expects, so put it back. */
- iPrecstart = ((iPrecstart + CRECBUFLEN - 1)
- % CRECBUFLEN);
- c = getinsync (qdaemon, TRUE);
- if (c == ZACK)
- break;
- /* FIXME: sz does a TCFLSH here */
- #if 0 /* FIXME: Not sure if this is needed, or where to put it. */
- /* ZCRCE - dinna wanna starta ping-pong game */
- if (!fzsend_data_packet (qdaemon, zZtx_packet_buf,
- 0, ZCRCE, TRUE))
- return FALSE;
- #endif
- if (c == ZRPOS) {
- if (qTsend == NULL
- || ! ffileisopen (qTsend->e)) {
- ulog (LOG_ERROR,
- "Attempt to back up non-file");
- return FALSE;
- }
- if (! ffileseek (qTsend->e,
- wpZrxpos - wpZtxstart)) {
- ulog (LOG_ERROR,
- "seek: %s", strerror (errno));
- return FALSE;
- }
- iZlast_tx_data_packet = -1; /* trigger ZDATA */
- break; /* not returning is intentional */
- }
- return FALSE;
- case XOFF:
- case XOFF | 0200:
- READCHAR (qdaemon, ch, XON_WAIT);
- break;
- case CR:
- break;
- default:
- iZjunk_count++;
- break;
- }
- }
-
- return TRUE;
- }
-
- /*
- * Wait for data to come in.
- *
- * This continues processing until a complete file or command has been
- * received.
- */
-
- boolean
- fzwait(qdaemon)
- struct sdaemon *qdaemon;
- {
- int c,cerr,rxcount;
- boolean fexit;
- achdrval_t rx_hdr;
-
- if (!fzstart_rx ())
- return FALSE;
-
- cerr = cZretries;
-
- goto nxthdr;
-
- for (;;) {
- if (!fzsend_hdr (qdaemon, ZHEX, ZRPOS,
- hvzencode_data_hdr (wpZrxbytes), FALSE))
- return FALSE;
- nxthdr:
- c = izrecv_hdr (qdaemon, rx_hdr);
-
- switch (c) {
- case ZM_TIMEOUT:
- case ZNAK:
- if (--cerr < 0) {
- ulog (LOG_ERROR, "fzwait: retries exhausted");
- return FALSE;
- }
- continue;
- case ZM_ERROR:
- if (--cerr < 0) {
- ulog (LOG_ERROR, "fzwait: retries exhausted");
- return FALSE;
- }
- /*fport_break ();*/
- continue;
- case ZM_RCDO:
- case ZFIN:
- return FALSE;
- case ZRPOS:
- case ZACK:
- goto nxthdr; /* ignore, partner is out of sync */
- case ZDATA: {
- winpos_t rx_bytes;
-
- zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
- DEBUG_MESSAGE2 (DEBUG_PROTO,
- "fzwait: bytes(us,them) 0x%lx,0x%lx",
- wpZrxbytes, rx_bytes);
- if (rx_bytes != wpZrxbytes) {
- if (--cerr < 0) {
- ulog (LOG_ERROR,
- "fzwait: retries exhausted");
- return FALSE;
- }
- (void) zrdat32 (qdaemon, zZrx_packet_buf,
- 1024, &rxcount);
- /*fport_break ();*/
- /*
- * FIXME: Seems to me we should ignore this one
- * and go for a timeout, the theory being
- * that the appropriate ZRPOS has already
- * been sent. We're obviously out of sync.
- * /dje 92Mar10
- */
- continue; /* goto nxthdr? */
- }
- moredata:
- /*
- * Do not call fgot_data() with (rxcount == 0) if it's
- * not ZCRCF. fgot_data() will erroneously think this
- * is the end of the message.
- */
- c = zrdat32 (qdaemon, zZrx_packet_buf, 1024,
- &rxcount);
- #if DEBUG > 1
- if (FDEBUGGING(DEBUG_PROTO)) {
- const char *msg;
-
- if (c < 0) {
- msg = ZZHEADER_NAME(c);
- } else {
- switch (c) {
- case GOTCRCW: msg = "ZCRCW"; break;
- case GOTCRCG: msg = "ZCRCG"; break;
- case GOTCRCQ: msg = "ZCRCQ"; break;
- case GOTCRCE: msg = "ZCRCE"; break;
- case GOTCRCF: msg = "ZCRCF"; break;
- default : msg = NULL; break;
- }
- }
- if (msg != NULL)
- DEBUG_MESSAGE2 (DEBUG_PROTO,
- "fzwait: zrdat32: %s, %d bytes",
- msg, rxcount);
- else
- DEBUG_MESSAGE2 (DEBUG_PROTO,
- "fzwait: zrdat32: %d, %d bytes",
- c, rxcount);
- }
- #endif
- switch (c) {
- case ZM_ERROR: /* CRC error */
- cZerrors++;
- if (--cerr < 0) {
- ulog (LOG_ERROR,
- "fzwait: retries exhausted");
- return FALSE;
- }
- /*fport_break ();*/
- continue;
- case ZM_TIMEOUT:
- cZtimeouts++;
- if (--cerr < 0) {
- ulog (LOG_ERROR,
- "fzwait: retries exhausted");
- return FALSE;
- }
- continue;
- case ZM_RCDO:
- return FALSE;
- case GOTCRCW:
- iZlast_rx_data_packet = ZCRCW;
- cerr = cZretries;
- if (rxcount != 0
- && !fgot_data (qdaemon, zZrx_packet_buf,
- (size_t) rxcount,
- (const char *) NULL,
- (size_t) 0,
- -1, -1, (long) -1,
- TRUE, &fexit))
- return FALSE;
- wpZrxbytes += rxcount;
- if (!fzsend_hdr (qdaemon, ZHEX, ZACK,
- hvzencode_data_hdr (wpZrxbytes),
- FALSE))
- return FALSE;
- if (! fsend_data (qdaemon->qconn, &xon,
- (size_t) 1, FALSE))
- return FALSE;
- goto nxthdr;
- case GOTCRCQ:
- iZlast_rx_data_packet = ZCRCQ;
- cerr = cZretries;
- if (rxcount != 0
- && !fgot_data (qdaemon, zZrx_packet_buf,
- (size_t) rxcount,
- (const char *) NULL,
- (size_t) 0,
- -1, -1, (long) -1,
- TRUE, &fexit))
- return FALSE;
- wpZrxbytes += rxcount;
- if (!fzsend_hdr (qdaemon, ZHEX, ZACK,
- hvzencode_data_hdr (wpZrxbytes),
- FALSE))
- return FALSE;
- goto moredata;
- case GOTCRCG:
- iZlast_rx_data_packet = ZCRCG;
- cerr = cZretries;
- if (rxcount != 0
- && !fgot_data (qdaemon, zZrx_packet_buf,
- (size_t) rxcount,
- (const char *) NULL,
- (size_t) 0,
- -1, -1, (long) -1,
- TRUE, &fexit))
- return FALSE;
- wpZrxbytes += rxcount;
- goto moredata;
- case GOTCRCE:
- iZlast_rx_data_packet = ZCRCE;
- cerr = cZretries;
- if (rxcount != 0
- && !fgot_data (qdaemon, zZrx_packet_buf,
- (size_t) rxcount,
- (const char *) NULL,
- (size_t) 0,
- -1, -1, (long) -1,
- TRUE, &fexit))
- return FALSE;
- wpZrxbytes += rxcount;
- goto nxthdr;
- case GOTCRCF:
- iZlast_rx_data_packet = ZCRCF;
- /*
- * fzfinish_rx() must be called before
- * fgot_data() because fgot_data() will send
- * out a UUCP-command but the sender won't be
- * ready for it until it receives our final
- * ZACK.
- */
- cerr = cZretries;
- wpZrxbytes += rxcount;
- if (!fzfinish_rx (qdaemon))
- return FALSE;
- if (!fgot_data (qdaemon, zZrx_packet_buf,
- (size_t) rxcount,
- (const char *) NULL,
- (size_t) 0, -1, -1,
- (long) -1, TRUE, &fexit))
- return FALSE;
- /*
- * FIXME: Examine <fexit>?
- * Or maybe ensure it's TRUE?
- */
- return TRUE;
- }
- return FALSE;
- }
- default:
- ulog (LOG_FATAL, "fzwait: received header %s",
- ZZHEADER_NAME(c));
- return FALSE;
- }
- }
-
- return TRUE;
- }
-
- /*
- * File level routine. Called when initiating/terminating file transfers.
- *
- * When starting to send a file: (TRUE, TRUE, cbytes)
- * When starting to receive a file: (TRUE, FALSE, -1)
- * When send EOF, check resend: (FALSE, TRUE, -1)
- * When receive EOF, check re-receive: (FALSE, FALSE, -1)
- */
-
- boolean
- fzfile(qdaemon, qtrans, fstart, fsend, cbytes, pfhandled)
- struct sdaemon *qdaemon;
- struct stransfer *qtrans;
- boolean fstart;
- boolean fsend;
- long cbytes;
- boolean *pfhandled;
- {
- long iredo;
-
- *pfhandled = FALSE;
-
- DEBUG_MESSAGE2 (DEBUG_PROTO, "fzfile: fstart=%d, fsend=%d", fstart,
- fsend);
-
- if (fsend) {
- if (fstart)
- return fzstart_tx ();
- if (! fzfinish_tx (qdaemon, &iredo))
- return FALSE;
- if (iredo >= 0) {
- if (! ffileisopen (qtrans->e)) {
- ulog (LOG_ERROR,
- "Attempt to back up non-file");
- return FALSE;
- }
- if (! ffileseek (qtrans->e, iredo)) {
- ulog (LOG_ERROR,
- "seek: %s", strerror (errno));
- return FALSE;
- }
- *pfhandled = TRUE;
- qtrans->fsendfile = TRUE;
- return fqueue_send (qdaemon, qtrans);
- }
- }
-
- return TRUE;
- }
-
- /****************************************************************************/
-
-
- #if 0 /* not used, we only use 32 bit crc's */
- /*
- * crctab calculated by Mark G. Mendel, Network Systems Corporation
- */
-
- static unsigned short crctab[256] = {
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
- 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
- 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
- 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
- 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
- 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
- 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
- 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
- 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
- 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
- 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
- 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
- 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
- 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
- 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
- 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
- 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
- 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
- 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
- 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
- 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
- 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
- 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
- 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
- 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
- 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
- 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
- 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
- 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
- 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
- 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
- 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
- };
- #endif /* crctab */
-
- /*
- * Copyright (C) 1986 Gary S. Brown. You may use this program, or
- * code or tables extracted from it, as desired without restriction.
- */
-
- /* First, the polynomial itself and its table of feedback terms. The */
- /* polynomial is */
- /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
- /* Note that we take it "backwards" and put the highest-order term in */
- /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
- /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
- /* the MSB being 1. */
-
- /* Note that the usual hardware shift register implementation, which */
- /* is what we're using (we're merely optimizing it by doing eight-bit */
- /* chunks at a time) shifts bits into the lowest-order term. In our */
- /* implementation, that means shifting towards the right. Why do we */
- /* do it this way? Because the calculated CRC must be transmitted in */
- /* order from highest-order term to lowest-order term. UARTs transmit */
- /* characters in order from LSB to MSB. By storing the CRC this way, */
- /* we hand it to the UART in the order low-byte to high-byte; the UART */
- /* sends each low-bit to hight-bit; and the result is transmission bit */
- /* by bit from highest- to lowest-order term without requiring any bit */
- /* shuffling on our part. Reception works similarly. */
-
- /* The feedback terms table consists of 256, 32-bit entries. Notes: */
- /* */
- /* The table can be generated at runtime if desired; code to do so */
- /* is shown later. It might not be obvious, but the feedback */
- /* terms simply represent the results of eight shift/xor opera- */
- /* tions for all combinations of data and CRC register values. */
- /* */
- /* The values must be right-shifted by eight bits by the "updcrc" */
- /* logic; the shift must be unsigned (bring in zeroes). On some */
- /* hardware you could probably optimize the shift in assembler by */
- /* using byte-swap instructions. */
-
- static unsigned long crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
- 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL,
- 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
- 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
- 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
- 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
- 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
- 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
- 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
- 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
- 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
- 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L,
- 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
- 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L,
- 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
- 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
- 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
- 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
- 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
- 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L,
- 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
- 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
- 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
- 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL,
- 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
- 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
- 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
- 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
- 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
- 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L,
- 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
- 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L,
- 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
- 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
- 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
- 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
- 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
- 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
- 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
- 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
- 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
- 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L,
- 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
- 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L,
- 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
- 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
- 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
- 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
- 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
- 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL,
- 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
- 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
- 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
- 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL,
- 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
- 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
- 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
- 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
- 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
- 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L,
- 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
- 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L,
- 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
- 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
- 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
- };
-
- /*
- * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
- * NOTE: First argument must be in range 0 to 255.
- * Second argument is referenced twice.
- *
- * Programmers may incorporate any or all code into their programs,
- * giving proper credit within the source. Publication of the
- * source routines is permitted so long as proper credit is given
- * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
- * Omen Technology.
- */
-
- #define updcrc(cp, crc) (crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
-
- #define UPDC32(b, crc) \
- (crc_32_tab[((unsigned)(crc) ^ (unsigned)(b)) & 0xff] \
- ^ (((crc) >> 8) & 0x00ffffffL))
-
- /****************************************************************************/
-
- /*
- * This section contains the guts of the Zmodem protocol. The intention
- * is to leave as much of it alone as possible at the start. Overtime it
- * will be cleaned up (EG: I'd like to clean up the naming of the globals).
- * Also, Zmodem has a different coding style. Over time this will be converted
- * to the Taylor UUCP coding style.
- */
-
- /*
- * Start the protocol (exchange init packets) ...
- *
- * UUCP can transfer files in both directions in one session. Therefore the
- * init sequence is a little different.
- *
- * 1) ZINIT packets are exchanged
- * - contains protocol version and protocol flags
- * 2) ZDATA packets are exchanged
- * - is intended to contain various numeric and string information
- * 3) ZACK packets are exchanged
- * 4) ZINITEND packets are exchanged
- */
-
- static boolean
- fzstart_proto(qdaemon)
- struct sdaemon *qdaemon;
- {
- int i;
- achdrval_t tx_hdr,rx_hdr;
-
- for (i = 0; i < cZstartup_retries; i++) {
- stohdr (0L, tx_hdr);
- tx_hdr[ZF0] = ZPROTOCOL_VERSION;
- if (fZesc_ctl)
- tx_hdr[ZF1] |= TX_ESCCTL;
- switch (izexchange_init (qdaemon, ZINIT, tx_hdr, rx_hdr)) {
- case -1: return FALSE;
- case 0: continue;
- case 1: break;
- }
- #if 0 /* can't work, but kept for documentation */
- if (rx_hdr[ZF0] == 0) {
- ulog (LOG_ERROR, "Old protocol version, init failed");
- return FALSE;
- }
- #endif
- fZesc_ctl = fZesc_ctl || (rx_hdr[ZF1] & TX_ESCCTL) != 0;
-
- stohdr (0L, tx_hdr);
- switch (izexchange_init (qdaemon, ZDATA, tx_hdr, rx_hdr)) {
- case -1: return FALSE;
- case 0: continue;
- case 1: break;
- }
-
- stohdr (0L, tx_hdr);
- switch (izexchange_init (qdaemon, ZACK, tx_hdr, rx_hdr)) {
- case -1: return FALSE;
- case 0: continue;
- case 1: break;
- }
-
- stohdr (0L, tx_hdr);
- switch (izexchange_init (qdaemon, ZINITEND, tx_hdr, rx_hdr)) {
- case -1: return FALSE;
- case 0: continue;
- case 1: break;
- }
-
- DEBUG_MESSAGE0 (DEBUG_PROTO,
- "fzstart_proto: Protocol started");
- return TRUE;
-
- /* FIXME: see protg.c regarding sequencing here. */
- }
-
- ulog (LOG_ERROR, "Protocol init failed");
- return FALSE;
- }
-
- /*
- * Exchange init messages. This is based on 'g'.
- * See the comments concerning fgexchange_init() in protg.c.
- *
- * We return 1 for success, 0 for restart, -1 for comm failure (terminate).
- */
-
- static int
- izexchange_init(qdaemon, send_type, send_val, recv_val)
- struct sdaemon *qdaemon;
- int send_type;
- achdrval_t send_val;
- achdrval_t recv_val;
- {
- int i,recv_type,count;
-
- for (i = 0; i < CEXCHANGE_INIT_RETRIES; i++) {
- if (!fzsend_hdr (qdaemon, send_type == ZDATA ? ZBIN : ZHEX,
- send_type, rclhdr (send_val), FALSE))
- return -1;
-
- /*
- * The ZDATA packet is intended to contain the <Attn> string
- * (eventually, if it's ever usable) and allow for anything
- * else that will need to be thrown in.
- */
-
- if (send_type == ZDATA) {
- count = czbuild_data_packet (zZtx_packet_buf, "",
- (size_t) 1, ZCRCF);
- if (!fsend_data (qdaemon->qconn, zZtx_packet_buf,
- (size_t) count, FALSE))
- return -1;
- }
-
- recv_type = izrecv_hdr (qdaemon, recv_val);
-
- switch (recv_type) {
- case ZM_TIMEOUT:
- case ZM_ERROR:
- continue;
- case ZM_RCDO:
- case ZFIN:
- return -1;
- case ZINIT:
- case ZACK:
- case ZINITEND:
- break;
- case ZDATA:
- if (zrdat32 (qdaemon, zZrx_packet_buf, 1024, &count)
- == GOTCRCF)
- break;
- continue;
- default:
- continue;
- }
-
- if (recv_type == send_type)
- return 1;
-
- /*
- * If the other side is farther along than we are, we have lost
- * a packet. Fall immediately back to ZINIT (but don't fail
- * if we are already doing ZINIT, since that would count
- * against cStart_retries more than it should).
- *
- * FIXME: The ">" test is "<" in protg.c. Check who's right.
- */
-
- if (recv_type > send_type && send_type != ZINIT)
- return 0;
-
- /*
- * If we are sending ZINITEND and we receive an ZINIT, the
- * other side has falled back (we know this because we have
- * seen a ZINIT from them). Fall back ourselves to start
- * the whole handshake over again.
- */
-
- if (recv_type == ZINIT && send_type == ZINITEND)
- return 0;
- }
-
- return 0;
- }
-
- /*
- * Shut down the protocol ...
- */
-
- static boolean
- fzshutdown_proto(qdaemon)
- struct sdaemon *qdaemon;
- {
- (void) fzsend_hdr (qdaemon, ZHEX, ZFIN, 0L, FALSE);
- return TRUE;
- }
-
- /*
- * Reset the transmitter side for sending a new message ...
- */
-
- static boolean
- fzstart_tx()
- {
- iZlast_tx_data_packet = -1;
-
- /*
- * <wpZlastsync> is set to -1L to suppress ZCRCW request otherwise
- * triggered by (wpZlastsync == wpZtxpos).
- */
-
- cZblklen = 1024;
- wpZlastsync = -1L;
- iZbeenhereb4 = 0;
- iZtleft = 0;
- iZjunk_count = 0;
-
- wpZtxpos = (wpZtxpos + 1024L) & ~1023L; /* next packet boundary */
- wpZlrxpos = wpZrxpos = wpZtxpos;
-
- wpZtxstart = wpZtxpos; /* so we can compute the "file offset" */
-
- return TRUE;
- }
-
- /*
- * Finish the sending of a message ...
- *
- * Basically, we wait for some indication that the receiver received our last
- * message. If the receiver tells us to restart from some point, we set
- * *plredo to that point.
- *
- * FIXME: This function is a major kludge at the moment. It is taken from
- * getinsync(). It is necessary because I don't yet buffer outgoing data.
- * It will go away when we do (buffer outgoing data).
- */
-
- static boolean
- fzfinish_tx(qdaemon, plredo)
- struct sdaemon *qdaemon;
- long *plredo;
- {
- int c,cerr,ctimeouts;
- achdrval_t rx_hdr;
- winpos_t rx_bytes;
-
- *plredo = -1;
- cerr = cZretries;
- ctimeouts = 0;
-
- DEBUG_MESSAGE4 (DEBUG_PROTO,
- "fzfinish_tx: txpos=0x%lx, rxpos=0x%lx, lrxpos=0x%lx, rxbytes=0x%lx",
- wpZtxpos, wpZrxpos, wpZlrxpos, wpZrxbytes);
-
- for (;;) {
- c = izrecv_hdr (qdaemon, rx_hdr);
-
- switch (c) {
- case ZRPOS:
- wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos,
- wpZlrxpos, wpZtxpos);
- /*
- * If the receiver sends a ZRPOS for the 1k block after
- * the one we're currently at, we lost the final ZACK.
- * We cheat and ignore this ZRPOS. Remember: the theory
- * is that this entire function will go away when we
- * begin buffering the outgoing data. Of course, one
- * can reword the protocol definition and say this
- * isn't cheating at all.
- */
- if (((wpZtxpos + 1024) & ~1023) == wpZrxpos)
- return TRUE;
- cZbytes_resent += wpZtxpos - wpZrxpos;
- wpZlrxpos = wpZtxpos = wpZrxpos;
- if (wpZlastsync == wpZrxpos) {
- if (++iZbeenhereb4 > 4)
- if (cZblklen > 32)
- cZblklen /= 2;
- /* FIXME: shouldn't we reset iZbeenhereb4? */
- }
- wpZlastsync = wpZrxpos;
- iZlast_tx_data_packet = ZCRCW; /* force a timeout */
- *plredo = wpZrxpos - wpZtxstart;
- return TRUE;
- case ZACK:
- wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos,
- wpZlrxpos, wpZtxpos);
- wpZlrxpos = wpZrxpos;
- if (wpZtxpos == wpZrxpos) /* the ACK we want? */
- return TRUE;
- break;
- case ZDATA:
- /*
- * We cheat here and take advantage of UUCP's current
- * half duplex nature. If we get a ZDATA starting on
- * the next 1k boundary, we lost the ZACK. We cheat and
- * tuck it away so that izrecv_hdr() can later detect
- * it. Remember: see above.
- */
- zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
- if (((wpZrxbytes + 1024L) & ~1023L) == rx_bytes) {
- iZpkt_rcvd_kludge = ZDATA;
- hvZpkt_hdrval_kludge = rclhdr (rx_hdr);
- return TRUE;
- }
- break; /* ignore, out of sync (old) */
- case ZNAK:
- /*
- * We cheat here and take advantage of UUCP's current
- * half duplex nature. If we get a ZNAK starting on
- * the next 1k boundary, we lost the ZACK. We cheat and
- * throw the ZNAK away. Remember: see above.
- *
- * On the other hand, if (rx_bytes == wpZrxbytes) then
- * the other side is also in fzfinish_tx(). He must
- * have lost our ZACK, so we send him another.
- */
- zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
- if (((wpZrxbytes + 1024L) & ~1023L) == rx_bytes)
- return TRUE;
- if (rx_bytes == wpZrxbytes) {
- if (!fzsend_hdr (qdaemon, ZHEX, ZACK,
- hvzencode_data_hdr (wpZrxbytes),
- TRUE))
- return FALSE;
- }
- break; /* ignore, out of sync (old) */
- case ZFIN:
- case ZM_RCDO:
- return FALSE;
- case ZM_TIMEOUT:
- if (--cerr < 0) {
- ulog (LOG_ERROR,
- "fzfinish_tx: retries exhausted");
- return FALSE;
- }
- /*
- * Normally the sender doesn't send NAK's for timeouts.
- * We have to here because of the following scenario:
- *
- * - We send ZDATA/ZCRCF
- * - They send ZACK (corrupted)
- * - They send ZDATA/ZCRCF (corrupted)
- *
- * At this point, both sides are in fzfinish_tx().
- * We only send ZNAK every second timeout to increase
- * our timeout delay vs. our partner. This tries to
- * avoid ZRPOS and ZNAK "passing in transit".
- */
- if (++ctimeouts % 2 == 0)
- if (!fzsend_hdr (qdaemon, ZHEX, ZNAK,
- hvzencode_data_hdr (wpZtxpos),
- TRUE))
- return FALSE;
- break;
- case ZM_ERROR:
- default:
- if (--cerr < 0) {
- ulog (LOG_ERROR,
- "fzfinish_tx: retries exhausted");
- return FALSE;
- }
- if (!fzsend_hdr (qdaemon, ZHEX, ZNAK,
- hvzencode_data_hdr (wpZtxpos),
- TRUE))
- return FALSE;
- break;
- }
- }
- }
-
- /*
- * Initialize the receiver ...
- */
-
- static boolean
- fzstart_rx()
- {
- wpZrxbytes = (wpZrxbytes + 1024L) & ~1023L; /* next packet boundary */
-
- return TRUE;
- }
-
- /*
- * Terminate the receiver ...
- *
- * Acknowledge the last packet received.
- */
-
- static boolean
- fzfinish_rx(qdaemon)
- struct sdaemon *qdaemon;
- {
- DEBUG_MESSAGE0 (DEBUG_PROTO, "fzfinish_rx: message/file received");
-
- return fzsend_hdr (qdaemon, ZHEX, ZACK,
- hvzencode_data_hdr (wpZrxbytes), FALSE);
- }
-
- /*
- * Send a Zmodem header to our partner ...
- */
-
- static boolean
- fzsend_hdr(qdaemon, ipkttype, ihdrtype, hdrval, fcheckreceive)
- struct sdaemon *qdaemon;
- int ipkttype;
- int ihdrtype;
- hdrval_t hdrval;
- boolean fcheckreceive;
- {
- int cpacketlen;
-
- DEBUG_MESSAGE2 (DEBUG_PROTO, "fzsend_hdr: %s, data = 0x%lx",
- ZZHEADER_NAME(ihdrtype), hdrval);
-
- cpacketlen = czbuild_header (zZtx_packet_buf, ipkttype,
- ihdrtype, hdrval);
-
- #ifdef DJE_TESTING
- #if 0
- if (ihdrtype == ZACK && rand () % 100 < uucptest2) {
- cZheaders_sent++;
- return TRUE;
- }
- #else
- if (ihdrtype == ZACK || ihdrtype == ZDATA) {
- boolean fresult;
- int old;
- extern int uucptest,uucptest2;
-
- old = uucptest;
- uucptest = uucptest2;
- cZheaders_sent++;
- fresult = fsend_data (qdaemon->qconn, zZtx_packet_buf,
- (size_t) cpacketlen, fcheckreceive);
- uucptest = old;
- return fresult;
- }
- #endif
- #endif
- cZheaders_sent++;
- return fsend_data (qdaemon->qconn, zZtx_packet_buf,
- (size_t) cpacketlen, fcheckreceive);
- }
-
- /*
- * Send a data packet to our partner ...
- * <frameend> is one of ZCRCx.
- */
-
- static boolean
- fzsend_data_packet(qdaemon, zdata, cdata, frameend, fcheckreceive)
- struct sdaemon *qdaemon;
- char *zdata;
- size_t cdata;
- int frameend;
- boolean fcheckreceive;
- {
- int cpacketlen;
-
- cpacketlen = czbuild_data_packet (zZtx_packet_buf, zdata, cdata,
- frameend);
-
- return fsend_data (qdaemon->qconn, zZtx_packet_buf,
- (size_t) cpacketlen, fcheckreceive);
- }
-
- /*
- * Build Zmodem headers ...
- *
- * Note that we use 32 bit CRC's for ZHEX headers.
- *
- * This function is a combination of zm fns: zsbhdr(), zsbh32(), and zshhdr().
- */
-
- static int
- czbuild_header(zresult, ipkttype, ihdrtype, hdrval)
- char *zresult;
- int ipkttype;
- int ihdrtype;
- hdrval_t hdrval;
- {
- char *p;
- int i;
- unsigned long crc;
- achdrval_t achdrval;
-
- p = zresult;
-
- switch (ipkttype) {
- case ZBIN:
- *p++ = ZPAD;
- *p++ = ZDLE;
- *p++ = ZBIN;
- p = zputchar (p, ihdrtype);
- crc = ICRCINIT;
- crc = UPDC32 (ihdrtype, crc);
- stohdr (hdrval, achdrval);
- for (i = 0; i < 4; i++) {
- p = zputchar (p, achdrval[i]);
- crc = UPDC32 (achdrval[i], crc);
- }
- crc = ~crc;
- for (i = 0; i < 4; i++) {
- p = zputchar (p, (char) crc);
- crc >>= 8;
- }
- break;
- case ZHEX: /* build hex header */
- *p++ = ZPAD;
- *p++ = ZPAD;
- *p++ = ZDLE;
- *p++ = ZHEX;
- p = zputhex (p, ihdrtype);
- crc = ICRCINIT;
- crc = UPDC32 (ihdrtype, crc);
- stohdr (hdrval, achdrval);
- for (i = 0; i < 4; i++) {
- p = zputhex (p, achdrval[i]);
- crc = UPDC32 (achdrval[i], crc);
- }
- crc = ~crc;
- for (i = 0; i < 4; i++) {
- p = zputhex (p, (char) crc);
- crc >>= 8;
- }
- *p++ = CR;
- /*
- * Uncork the remote in case a fake XOFF has stopped data flow.
- */
- if (ihdrtype != ZFIN && ihdrtype != ZACK) /* FIXME: why? */
- *p++ = XON;
- break;
- default:
- ulog (LOG_FATAL, "czbuild_header: ipkttype == %d", ipkttype);
- break;
- }
-
- return p - zresult;
- }
-
- /*
- * Build Zmodem data packets ...
- *
- * This function is zsdata() and zsda32() from the zm source.
- */
-
- static int
- czbuild_data_packet(zresult, zdata, cdata, frameend)
- char *zresult;
- const char *zdata;
- size_t cdata;
- int frameend;
- {
- char *p;
- unsigned long crc;
-
- p = zresult;
-
- crc = ICRCINIT;
- for ( ; cdata-- != 0; zdata++) {
- char c;
-
- c = *zdata;
- if (c & 0140)
- *p++ = c;
- else
- p = zputchar (p, c);
- crc = UPDC32 ((unsigned char) c, crc);
- }
- *p++ = ZDLE;
- *p++ = frameend;
- crc = UPDC32 (frameend, crc);
- crc = ~crc;
- for (cdata = 0; cdata < 4; cdata++) {
- p = zputchar (p, (char) crc);
- crc >>= 8;
- }
- if (frameend == ZCRCW || frameend == ZCRCE || frameend == ZCRCF) {
- *p++ = CR;
- *p++ = XON;
- }
-
- return p - zresult;
- }
-
- /*
- * Read in a header ...
- *
- * This is function zgethdr() from the Zmodem source.
- */
-
- static int
- izrecv_hdr(qdaemon, hdr)
- struct sdaemon *qdaemon;
- achdrval_t hdr;
- {
- int c,cerr;
-
- /*
- * Kludge alert! If another part of the program received a packet but
- * wasn't ready to handle it, it is tucked away for us to handle now.
- */
-
- if (iZpkt_rcvd_kludge != -1) {
- c = iZpkt_rcvd_kludge;
- iZpkt_rcvd_kludge = -1;
- stohdr (hvZpkt_hdrval_kludge, hdr);
- DEBUG_MESSAGE2 (DEBUG_PROTO,
- "izrecv_hdr: queued %s, data = 0x%lx",
- ZZHEADER_NAME(c), rclhdr (hdr));
- cZheaders_received++;
- return c;
- }
-
- cerr = cZmax_garbage; /* Max bytes before start of frame */
-
- again:
- switch (c = noxrd7 (qdaemon)) {
- case ZM_TIMEOUT:
- case ZM_ERROR:
- case ZM_RCDO:
- goto fifi;
- case ZPAD: /* This is what we want */
- break;
- case CR: /* padding at end of previous header */
- default:
- if (--cerr < 0) {
- c = ZM_ERROR;
- goto fifi;
- }
- goto again;
- }
-
- splat:
- switch (c = noxrd7 (qdaemon)) {
- case ZPAD:
- if (--cerr < 0) {
- c = ZM_ERROR;
- goto fifi;
- }
- goto splat;
- case ZM_TIMEOUT:
- case ZM_RCDO:
- goto fifi;
- case ZDLE: /* This is what we want */
- break;
- default:
- if (--cerr < 0) {
- c = ZM_ERROR;
- goto fifi;
- }
- goto again;
- }
-
- switch (c = noxrd7 (qdaemon)) {
- case ZM_TIMEOUT:
- case ZM_RCDO:
- goto fifi;
- case ZBIN:
- c = zrbhdr32 (qdaemon, hdr);
- break;
- case ZHEX:
- c = zrhhdr (qdaemon, hdr);
- break;
- default:
- if (--cerr < 0) {
- c = ZM_ERROR;
- goto fifi;
- }
- goto again;
- }
-
- fifi:
- switch (c) {
- case ZM_TIMEOUT:
- cZtimeouts++;
- break;
- case ZM_ERROR:
- cZerrors++;
- break;
- case ZM_RCDO:
- break;
- default:
- cZheaders_received++;
- break;
- }
- DEBUG_MESSAGE2 (DEBUG_PROTO, "izrecv_hdr: %s, data = 0x%lx",
- ZZHEADER_NAME(c), rclhdr (hdr));
-
- return c;
- }
-
- /*
- * Receive a binary style header (type and position) with 32 bit FCS ...
- */
-
- static int
- zrbhdr32(qdaemon, hdr)
- struct sdaemon *qdaemon;
- achdrval_t hdr;
- {
- int c,i,type;
- unsigned long crc;
-
- if ((c = zdlread (qdaemon)) & ~0377)
- return c;
- type = c;
- crc = ICRCINIT;
- crc = UPDC32 (c, crc);
-
- for (i = 0; i < 4; i++) {
- if ((c = zdlread (qdaemon)) & ~0377)
- return c;
- crc = UPDC32 (c, crc);
- hdr[i] = (char) c;
- }
- for (i = 0; i < 4; i++) {
- if ((c = zdlread (qdaemon)) & ~0377)
- return c;
- crc = UPDC32 (c, crc);
- }
- if (crc != IHDRCRC)
- return ZM_ERROR;
-
- return type;
- }
-
- /*
- * Receive a hex style header (type and position) ...
- */
-
- static int
- zrhhdr(qdaemon, hdr)
- struct sdaemon *qdaemon;
- achdrval_t hdr;
- {
- int c,i,type;
- unsigned long crc;
-
- if ((c = zgethex (qdaemon)) < 0)
- return c;
- type = c;
- crc = ICRCINIT;
- crc = UPDC32 (c, crc);
-
- for (i = 0; i < 4; i++) {
- if ((c = zgethex (qdaemon)) < 0)
- return c;
- crc = UPDC32 (c, crc);
- hdr[i] = (char) c;
- }
- for (i = 0; i < 4; i++) {
- if ((c = zgethex (qdaemon)) < 0)
- return c;
- crc = UPDC32 (c, crc);
- }
- if (crc != IHDRCRC)
- return ZM_ERROR;
-
- return type;
- }
-
- /*
- * Receive a data packet ...
- */
-
- static int
- zrdat32(qdaemon, buf, length, iprxcount)
- struct sdaemon *qdaemon;
- char *buf;
- int length;
- int *iprxcount;
- {
- int c,d;
- unsigned long crc;
- char *end;
-
- crc = ICRCINIT;
- *iprxcount = 0;
- end = buf + length;
- while (buf <= end) {
- if ((c = zdlread (qdaemon)) & ~0377) {
- crcfoo:
- switch (c) {
- case GOTCRCE:
- case GOTCRCG:
- case GOTCRCQ:
- case GOTCRCW:
- case GOTCRCF:
- d = c;
- c &= 0377;
- crc = UPDC32 (c, crc);
- if ((c = zdlread (qdaemon)) & ~0377)
- goto crcfoo;
- crc = UPDC32 (c, crc);
- if ((c = zdlread (qdaemon)) & ~0377)
- goto crcfoo;
- crc = UPDC32 (c, crc);
- if ((c = zdlread (qdaemon)) & ~0377)
- goto crcfoo;
- crc = UPDC32 (c, crc);
- if ((c = zdlread (qdaemon)) & ~0377)
- goto crcfoo;
- crc = UPDC32 (c, crc);
- if (crc != IHDRCRC)
- return ZM_ERROR;
- *iprxcount = length - (end - buf);
- return d;
- case ZM_TIMEOUT:
- case ZM_RCDO:
- return c;
- default:
- return ZM_ERROR;
- }
- }
- *buf++ = (char) c;
- crc = UPDC32 (c, crc);
- }
-
- return ZM_ERROR; /* bad packet, too long */
- }
-
- /*
- * Respond to receiver's complaint, get back in sync with receiver ...
- */
-
- static int
- getinsync(qdaemon, flag)
- struct sdaemon *qdaemon;
- boolean flag;
- {
- int c,cerr;
- achdrval_t rx_hdr;
-
- cerr = cZretries;
-
- for (;;) {
- c = izrecv_hdr (qdaemon, rx_hdr);
-
- switch (c) {
- case ZRPOS:
- wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos,
- wpZlrxpos, wpZtxpos);
- cZbytes_resent += wpZtxpos - wpZrxpos;
- wpZlrxpos = wpZtxpos = wpZrxpos;
- if (wpZlastsync == wpZrxpos) {
- if (++iZbeenhereb4 > 4)
- if (cZblklen > 32)
- cZblklen /= 2;
- /* FIXME: shouldn't we reset iZbeenhereb4? */
- }
- wpZlastsync = wpZrxpos;
- return ZRPOS;
- case ZACK:
- wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos,
- wpZlrxpos, wpZtxpos);
- wpZlrxpos = wpZrxpos;
- if (flag || wpZtxpos == wpZrxpos)
- return ZACK;
- break;
- case ZNAK: {
- winpos_t rx_bytes;
- /*
- * Our partner is in fzfinish_tx() and is waiting
- * for ZACK ...
- */
- zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
- if (rx_bytes == wpZrxbytes) {
- if (!fzsend_hdr (qdaemon, ZHEX, ZACK,
- hvzencode_data_hdr (wpZrxbytes),
- TRUE))
- return FALSE;
- }
- break;
- }
- case ZFIN:
- case ZM_RCDO:
- return c;
- case ZM_TIMEOUT:
- if (--cerr < 0) {
- ulog (LOG_ERROR,
- "getinsync: retries exhausted");
- return ZM_ERROR;
- }
- break; /* sender doesn't send ZNAK for timeout */
- case ZM_ERROR:
- default:
- if (--cerr < 0) {
- ulog (LOG_ERROR,
- "getinsync: retries exhausted");
- return ZM_ERROR;
- }
- if (!fzsend_hdr (qdaemon, ZHEX, ZNAK,
- hvzencode_data_hdr (wpZtxpos),
- TRUE))
- return ZM_ERROR;
- break;
- }
- }
- }
-
- /*
- * Send a byte as two hex digits ...
- */
-
- static char *
- zputhex(p, ch)
- char *p;
- int ch;
- {
- static char digits[] = "0123456789abcdef";
-
- *p++ = digits[(ch & 0xF0) >> 4];
- *p++ = digits[ch & 0xF];
- return p;
- }
-
- /*
- * Send character c with ZMODEM escape sequence encoding ...
- *
- * Escape XON, XOFF.
- * FIXME: Escape CR following @ (Telenet net escape) ... disabled for now
- * Will need to put back references to <lastsent>.
- */
-
- static char *
- zputchar(p, ch)
- char *p;
- int ch;
- {
- char c = ch;
-
- /* Quick check for non control characters */
-
- if (c & 0140) {
- *p++ = c;
- } else {
- switch (c & 0377) {
- case ZDLE:
- *p++ = ZDLE;
- *p++ = c ^ 0100;
- break;
- case CR:
- #if 0
- if (!fZesc_ctl && (lastsent & 0177) != '@')
- goto sendit;
- #endif
- /* fall through */
- case 020: /* ^P */
- case XON:
- case XOFF:
- *p++ = ZDLE;
- c ^= 0100;
- /*sendit:*/
- *p++ = c;
- break;
- default:
- if (fZesc_ctl && !(c & 0140)) {
- *p++ = ZDLE;
- c ^= 0100;
- }
- *p++ = c;
- break;
- }
- }
-
- return p;
- }
-
- /*
- * Decode two lower case hex digits into an 8 bit byte value ...
- */
-
- static int
- zgethex(qdaemon)
- struct sdaemon *qdaemon;
- {
- int c,n;
-
- if ((c = noxrd7 (qdaemon)) < 0)
- return c;
- n = c - '0';
- if (n > 9)
- n -= ('a' - ':');
- if (n & ~0xF)
- return ZM_ERROR;
- if ((c = noxrd7 (qdaemon)) < 0)
- return c;
- c -= '0';
- if (c > 9)
- c -= ('a' - ':');
- if (c & ~0xF)
- return ZM_ERROR;
- c += (n << 4);
-
- return c;
- }
-
- /*
- * Read a byte, checking for ZMODEM escape encoding ...
- */
-
- static int
- zdlread(qdaemon)
- struct sdaemon *qdaemon;
- {
- int c;
-
- again:
- READCHAR (qdaemon, c, cZtimeout);
- if (c < 0)
- return c;
- if (c & 0140) /* quick check for non control characters */
- return c;
- switch (c) {
- case ZDLE:
- break;
- case XON:
- goto again;
- case XOFF:
- READCHAR (qdaemon, c, XON_WAIT);
- goto again;
- default:
- if (fZesc_ctl && !(c & 0140))
- goto again;
- return c;
- }
-
- again2:
- READCHAR (qdaemon, c, cZtimeout);
- if (c < 0)
- return c;
- switch (c) {
- case ZCRCE:
- case ZCRCG:
- case ZCRCQ:
- case ZCRCW:
- case ZCRCF:
- return c | GOTOR;
- case ZRUB0: /* FIXME: This is never generated. */
- return 0177;
- case ZRUB1: /* FIXME: This is never generated. */
- return 0377;
- case XON:
- goto again2;
- case XOFF:
- READCHAR (qdaemon, c, XON_WAIT);
- goto again2;
- default:
- if (fZesc_ctl && !(c & 0140))
- goto again2; /* FIXME: why again2? */
- if ((c & 0140) == 0100)
- return c ^ 0100;
- break;
- }
-
- return ZM_ERROR;
- }
-
- /*
- * Read a character from the modem line with timeout ...
- * Eat parity bit, XON and XOFF characters.
- */
-
- static int
- noxrd7(qdaemon)
- struct sdaemon *qdaemon;
- {
- int c;
-
- for (;;) {
- READCHAR (qdaemon, c, cZtimeout);
- if (c < 0)
- return c;
- switch (c &= 0177) {
- case XON:
- continue;
- case XOFF:
- READCHAR (qdaemon, c, XON_WAIT);
- continue;
- case CR:
- case ZDLE:
- return c;
- default:
- if (fZesc_ctl && !(c & 0140))
- continue;
- return c;
- }
- }
- }
-
- /*
- * Read a character from the receive buffer, or from the line if empty ...
- *
- * <timeout> is in seconds (maybe make it tenths of seconds like in Zmodem?)
- */
-
- static int
- realreadchar(qdaemon, timeout)
- struct sdaemon *qdaemon;
- int timeout;
- {
- int c;
-
- if ((c = breceive_char (qdaemon->qconn, timeout, TRUE)) >= 0)
- return c;
-
- switch (c) {
- case -1:
- return ZM_TIMEOUT;
- case -2:
- return ZM_RCDO;
- }
-
- ulog (LOG_FATAL, "realreadchar: breceive_char() returned %d", c);
- return ZM_ERROR;
- }
-
-
- /*
- * Check if the receive channel has any characters in it.
- *
- * At present we can only test the receive buffer. No mechanism is available
- * to go to the hardware. This should not be a problem though, as long as all
- * appropriate calls to fsend_data() set <fdoread> to TRUE.
- */
-
- static boolean
- fzreceive_ready()
- {
- return iPrecstart != iPrecend;
- }
-
- /*
- * Store integer value in an achdrval_t ...
- */
-
- static void
- stohdr(val, hdr)
- hdrval_t val;
- achdrval_t hdr;
- {
- hdr[ZP0] = (char) val;
- hdr[ZP1] = (char) (val >> 8);
- hdr[ZP2] = (char) (val >> 16);
- hdr[ZP3] = (char) (val >> 24);
- }
-
- /*
- * Recover an integer from a header ...
- */
-
- static hdrval_t
- rclhdr(hdr)
- achdrval_t hdr;
- {
- hdrval_t v;
-
- v = hdr[ZP3] & 0377;
- v = (v << 8) | (hdr[ZP2] & 0377);
- v = (v << 8) | (hdr[ZP1] & 0377);
- v = (v << 8) | (hdr[ZP0] & 0377);
-
- return v;
- }
-
- /*
- * Encode a <hdrval_t> from the byte count ...
- *
- * We use to store the byte count / 32 and a message sequence number which
- * made this function very useful. Don't remove it.
- * FIXME: Well, maybe remove it later.
- */
-
- static hdrval_t
- hvzencode_data_hdr(cbytes)
- winpos_t cbytes;
- {
- return (hdrval_t) cbytes;
- }
-
- /*
- * Decode a <hdrval_t> into a byte count ...
- *
- * We use to store the byte count / 32 and a message sequence number which
- * made this function very useful. Don't remove it.
- * FIXME: Well, maybe remove it later.
- */
-
- static void
- zdecode_data_hdr(hdrval, pcbytes)
- hdrval_t hdrval;
- winpos_t *pcbytes;
- {
- *pcbytes = hdrval;
- }
-
- /*
- * Update <wpZrxpos> from the received data header value ...
- *
- * FIXME: Here is where we'd handle wrapping around at 4 gigabytes.
- */
-
- static winpos_t
- lzupdate_rxpos(rx_hdr, rxpos, lrxpos, txpos)
- achdrval_t rx_hdr;
- winpos_t rxpos,lrxpos,txpos;
- {
- winpos_t rx_pktpos;
-
- zdecode_data_hdr (rclhdr (rx_hdr), &rx_pktpos);
-
- DEBUG_MESSAGE4 (DEBUG_PROTO,
- "lzupdate_rxpos: rx_pktpos=0x%lx, rxpos=0x%lx, lrxpos=0x%lx, txpos=0x%lx",
- rx_pktpos, rxpos, lrxpos, txpos);
-
- /*
- * Check if <rx_pktpos> valid. It could be old.
- */
-
- if (rx_pktpos < wpZlrxpos
- || rx_pktpos > ((wpZtxpos + 1024L) & ~1023L))
- return rxpos;
-
- return rx_pktpos;
- }
-